package com.friend.chat.base

import android.content.Context
import android.widget.Toast
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.friend.chat.net.ServerRepository

import kotlinx.coroutines.*
import retrofit2.HttpException
import java.net.ConnectException
import java.net.SocketTimeoutException
import java.net.UnknownHostException

/**
 * @des 作用：继承 AndroidViewModel 的功能，添加toast 功能
 * @date 2021/7/2
 * @author gorilla
 */
typealias Block<T> = suspend (CoroutineScope) -> T
typealias Error = suspend (Exception) -> Unit
typealias Cancel = suspend (Exception) -> Unit

open class BasicViewModel : AndroidViewModel(MyApplication.mApplication),
    CoroutineScope by MainScope() {

    val mRepository by lazy { ServerRepository() }
    val mContext: Context by lazy { getApplication<MyApplication>() }
    val loadStatus by lazy { MutableLiveData<LoadState>() }
    val refreshingStatus by lazy { MutableLiveData<RefreshingState>() }

    /**
     * 创建并执行协程
     * @param successResult 协程中执行
     * @param errorResult 错误时执行
     * @param cancel 取消时只需
     * @param showErrorToast 是否弹出错误吐司
     * @return Job
     */
    protected fun netWorkJob(
        successResult: Block<Unit>,
        errorResult: Error? = null,
        cancel: Cancel? = null,
        showErrorToast: Boolean = true
    ): Job {
        return viewModelScope.launch {
            try {
                successResult.invoke(this)
            } catch (e: Exception) {
                when (e) {
                    is CancellationException -> {
                        cancel?.invoke(e)
                    }
                    else -> {
                        onError(e, showErrorToast)
                        errorResult?.invoke(e)
                    }
                }
            }
        }
    }

    /**
     * 统一处理错误
     * @param e 异常
     * @param showErrorToast 是否显示错误吐司
     */
    private fun onError(e: Exception, showErrorToast: Boolean) {
        when (e) {
            // 网络请求失败
            is ConnectException, is SocketTimeoutException, is UnknownHostException, is HttpException ->
                if (showErrorToast) toast("Network request failed")
            // 其他错误
            else ->
                if (showErrorToast) toast(e.message ?: return)
        }
    }


    open fun toast(message: String) {
        Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show()
    }

}

